#ifdef __cplusplus
extern "C"{
#endif
#include "xs_def.h"
#include "xs_message.h"
#include "xs_log.h"
#include "xs_malloc.h"
#include "xs_string.h"
//#include "xs.h"

#define __MALLOC_TEST_ONLY_


static t_queue_global q_data;
static unsigned long mem_alloc_count = 0;


#ifdef __MALLOC_TEST_ONLY_
void xs_show_malloc_count()
{
    	xs_logd("memory alloc count :%ld \n",mem_alloc_count);
}
#endif

static void *xs_mem_malloc(unsigned long size) 
{
	void *memp = xs_malloc(size);

	if(memp == NULL)
		xs_logd("sys_malloc() , malloc()failed ! S %ld \n",size);

	mem_alloc_count++;

	return (memp);
}
static void xs_mem_free(void *memp) 
{
	if(memp == NULL)
	    xs_logd("mem_free (): NULL memp");
	else
	    xs_free(memp);

	mem_alloc_count--;
}

static int xs_msgque_mutex_create(xs_pthread_mutex_t *pmutex) 
{
    xs_pthread_mutex_init(pmutex, NULL);
    return (__message_success__);
}
static int xs_msgque_mutex_lock(xs_pthread_mutex_t *pmutex)
{
    xs_pthread_mutex_lock(pmutex);
    return (__message_success__);
}


static int xs_msgque_mutex_unlock(xs_pthread_mutex_t *pmutex)
{
    xs_pthread_mutex_unlock(pmutex);
    return (__message_success__);
}

static int xs_msgque_sem_create(char *pname, xs_semid *psemid)
{
	xs_scb *pscb = NULL;
	int semindex;
	*psemid = (xs_semid)NULL;

	if(pname == NULL)
	{
		xs_logd("msgque_sem_create() pname == NULL !\n");
		return (__message_unsuccess__);
	}
	xs_msgque_mutex_lock(&q_data.g_sem_mutex);
	semindex = q_data.semnum;  
	if(semindex >= OS_WRAP_MAX_SEMS)
	{
		xs_msgque_mutex_unlock(&q_data.g_sem_mutex);
		xs_logd("msgque_sem_create(), semindex > max sems limit \n");

		return (__message_unsuccess__);
	}
	pscb = &(q_data.scb_array[semindex]);  
	if(xs_msgque_mutex_create(&pscb->sem_mutex) != __message_success__)
	{
		xs_msgque_mutex_unlock(&q_data.g_sem_mutex);
		xs_logd("msgque_sem_create(),msgque_mutex_create(&pscb->sem_mutex) failed\n");

		return (__message_unsuccess__);
	}
	if(xs_pthread_cond_init(&pscb->cond_var,NULL) != 0)    
	{
		xs_pthread_mutex_destroy(&pscb->sem_mutex);
		xs_msgque_mutex_unlock(&q_data.g_sem_mutex);
		xs_logd("msgque_sem_create(),pthread_cond_init(&pscb->cond_var,NULL) failed\n");

		return (__message_unsuccess__);
	}

	pscb->semid = semindex + 1; 
	pscb->sem_count = 0;
	q_data.semnum++;
	*psemid = pscb->semid;
	xs_memcpy(pscb->name, pname, sizeof(pscb->name) - 1);
	xs_msgque_mutex_unlock(&q_data.g_sem_mutex);
	
	return (__message_success__);
}

static int xs_msgque_sem_release(xs_semid semid)
{
    xs_scb *pscb;
	int semindex;

	for(semindex=0;semindex < q_data.semnum;semindex++)
		if(q_data.scb_array[semindex].semid == semid)
			break;

	if(semindex >= q_data.semnum)
	{
		xs_logd("msgque_sem_release(); semindex > q_data.semnum ,No such semid ! \n");
		return (__message_id_not_exsit__);
	}
	
	pscb = &q_data.scb_array[semindex];
	xs_msgque_mutex_lock(&pscb->sem_mutex);
	pscb->sem_count++;  
	
	if(pscb->sem_count == 1)
		xs_pthread_cond_signal(&pscb->cond_var);  
	
	xs_msgque_mutex_unlock(&pscb->sem_mutex);
	
	return (__message_success__);
}

static int xs_msgque_sem_wait(xs_semid semid)
{
	xs_scb *pscb;
	int semindex;

	for(semindex = 0;semindex < q_data.semnum;semindex++)
		if(q_data.scb_array[semindex].semid == semid)
			break;
	if(semindex >= q_data.semnum)
	{
		xs_logd("msgque_sem_wait(); semindex > q_data.semnum ,No such semid ! \n");
		return (__message_id_not_exsit__);
	}

	pscb = &q_data.scb_array[semindex];

	xs_msgque_mutex_lock(&pscb->sem_mutex);

	if(pscb->sem_count == 0)  
		if(xs_pthread_cond_wait(&pscb->cond_var,&pscb->sem_mutex) != 0)
			return (__message_unsuccess__);
		
	if(pscb->sem_count > 0)
		pscb->sem_count--;  
	
	xs_msgque_mutex_unlock(&pscb->sem_mutex);

	return (__message_success__);
}
unsigned long xs_msgque_create(char *p_name)
{
    xs_qcb *pqcb = NULL;
    int qindex;
    xs_queid queid;

    if(p_name == NULL)
    {
        xs_logd("sys_msgque_create();p_name == NULL \n");
        return (__message_unsuccess__);
    }
    xs_msgque_mutex_lock(&q_data.g_que_mutex);
    qindex = q_data.que_num; 
    if(qindex >= OS_WRAP_MAX_QUEUES)
    {
        xs_msgque_mutex_unlock(&q_data.g_que_mutex);
        xs_logd("sys_msgque_create(); qindex >= OS_WARP_MAX_QUEUES \n");

        return (__message_unsuccess__);
    }

    pqcb = &(q_data.qcb_array[qindex]);

    if(xs_msgque_sem_create(p_name, &pqcb->semid) != __message_success__)
    {
        xs_logd("sys_msgque_create(); msgque_sem_create() != 0 \n");
        xs_msgque_mutex_unlock(&q_data.g_que_mutex);
        return (__message_unsuccess__);
    }

    if(xs_msgque_mutex_create(&pqcb->qmutex) != __message_success__)
    {
        xs_logd("sys_msgque_create(); msgque_mutex_create() != 0 \n");
        xs_msgque_mutex_unlock(&q_data.g_que_mutex);
        return (__message_unsuccess__);
    }
    pqcb->firstp = pqcb->lastp;    
    q_data.que_num++;
    queid = qindex + 1;    
    xs_memcpy(pqcb->name,p_name,sizeof(pqcb->name)-1);   
    pqcb->name[sizeof(pqcb->name)-1] = '\x0';
    xs_msgque_mutex_unlock(&q_data.g_que_mutex);

    return queid;

}

unsigned short xs_msgque_send(unsigned long qid, void *msg, unsigned short msglen)
{
    xs_msg_block *pbmsg;
    xs_qcb *pqcb;
    unsigned long qindex;

    if(msg == NULL)
    {
        xs_logd("sys_msgque_send(),msg == NULL \n");
        return (__message_unsuccess__);
    }

    qindex = qid - 1;

    if(qindex >= OS_WRAP_MAX_QUEUES)
    {
        xs_logd("sys_msgque_send();qid error\n");
        return (__message_unsuccess__);
    }

    pqcb = &(q_data.qcb_array[qindex]);

    pbmsg = (xs_msg_block *)xs_mem_malloc(sizeof(xs_msg_block));

    if(pbmsg == NULL)
    {
        xs_logd("sys_msgque_send(),mem_malloc pbmsg == NULL \n");
        return (__message_unsuccess__);
    }

    pbmsg->nextp = NULL;    
    pbmsg->msg = msg;   
    pbmsg->msglen = msglen;  

	xs_msgque_mutex_lock(&pqcb->qmutex);

    if(pqcb->lastp != NULL)
    {
        pqcb->lastp->nextp = pbmsg;
        pqcb->lastp = pbmsg;
    }
    else
    {
        pqcb->firstp = pqcb->lastp = pbmsg;
    }

    xs_msgque_sem_release(pqcb->semid); 

    xs_msgque_mutex_unlock(&pqcb->qmutex);

    return (__message_success__);

}
unsigned short xs_msgque_recv(unsigned long qid,void **msg,unsigned short *msglen)
{
    xs_msg_block *pbmsg;
    xs_qcb *pqcb;
    unsigned long qindex;

    pbmsg = NULL;
    qindex = qid - 1;

    if(qindex >= OS_WRAP_MAX_QUEUES)
    {
        xs_logd("sys_msgque_recv(); qindex >= limit \n");
        return (__message_unsuccess__);
    }

    pqcb = &q_data.qcb_array[qindex];

    if(xs_msgque_sem_wait(pqcb->semid) != __message_success__)
    {
        xs_logd("sys_msgque_recv(); msgque_sem_wait () failed \n");
        return (__message_unsuccess__);
    }

    xs_msgque_mutex_lock(&pqcb->qmutex);

    pbmsg = pqcb->firstp;   

    if(pbmsg == NULL)
    {
        xs_logd("sys_msgque_recv(); pbmsg == NULL \n");
        xs_msgque_mutex_unlock(&pqcb->qmutex);
        return (__message_unsuccess__);
    }

    *msg = pbmsg->msg;   
    *msglen = pbmsg->msglen;   

    if(pqcb->lastp == pbmsg) 
    {
        pqcb->lastp = NULL;
    }
    pqcb->firstp = pbmsg->nextp;

    xs_mem_free(pbmsg); 
    xs_msgque_mutex_unlock(&pqcb->qmutex);

    return (__message_success__);

}


int xs_msgque_init(void)
{
    xs_pthread_mutex_init(&q_data.g_mutex,NULL);
    xs_pthread_mutex_init(&q_data.g_que_mutex,NULL);
    xs_pthread_mutex_init(&q_data.g_sem_mutex,NULL);
	
    q_data.que_num = 0;
    q_data.semnum = 0;

    return (__message_success__);
}


unsigned long netrecv_id; 
unsigned long netsend_id;
unsigned long ppcrecv_id; 
unsigned long ppcsend_id; 
int xs_message_queue_test(void)
{

	char *msg= "Hello the crule world\n";
	char *send_msg;
	void *recv_buff = NULL;
	unsigned short int msglen = 0;
	int i = 0;

	send_msg = (char *)xs_malloc(xs_strlen(msg) + 1);
	xs_memcpy(send_msg, msg, xs_strlen(msg));
	*(send_msg + xs_strlen(msg)) = '\0';

	xs_msgque_init();

	netrecv_id = xs_msgque_create("net_recv");

	netsend_id = xs_msgque_create("net_send");

	ppcrecv_id = xs_msgque_create("uart_recv");

	ppcsend_id = xs_msgque_create("uart_recv");
	
	
	xs_logd("net_recv: %ld  net_send: %ld  ppc_recv: %ld ppc_send: %ld\n", netrecv_id, netsend_id, ppcrecv_id, ppcsend_id);

	xs_msgque_send(netsend_id, (void*)send_msg, xs_strlen(send_msg));
	xs_msgque_recv(netsend_id, (void **)&recv_buff,&msglen);
	
	for(i = 0; i < msglen; i++)
	    printf("%c ", *((char *)(recv_buff + i)));
	printf("\n");
	
	xs_free(recv_buff);

	return 0;
}

#ifdef __cplusplus
}
#endif
